#include "GameEngine.h"
#include "GameConfig.h"


GameEngine::GameEngine(void)
	: state(INIT_STATE), data(GB::MaxRow, GB::MaxLine), ai(new AI(&data)), aiThr(this),
      recordType(GB::CHESS_BLACK)
{
}


GameEngine::~GameEngine(void)
{
    delete ai;
}

void GameEngine::ProcessNew()
{
	data.Init();
    if (GameConfig::Instance()->Mode() == GB::MOD_AI_BLACK)
    {
        state = AI_STATE;
        aiThr.start();
    }
    else
    {
	    state = BLACK_STATE;
    }
}

GB::GAME_RESULT GameEngine::GetResult(int row, int line)
{
	GB::GAME_RESULT result = data.Judge(row, line);

	if (result != GB::NO_WIN)
		state = FINAL_STATE;

	return result;
}

int GameEngine::GetEval(GB::CHESS_TYPE type)
{
	return data.Eval(type);
}

void GameEngine::SetLevel(int level)
{
    ai->SetSearchDepth(level + 1);
}

void GameEngine::AIThrFunc()
{
    int row;
    int line;
    GB::CHESS_TYPE type = GB::CHESS_BLACK;
    GAME_STATE nextState = WHITE_STATE;

    if (GameConfig::Instance()->Mode() == GB::MOD_AI_WHITE)
    {
        type = GB::CHESS_WHITE;
        nextState = BLACK_STATE;
    }

    ai->GetBestPos(row, line, type);
    data.Place(row, line, type);

    emit Order(row, line, type);

    this->state = nextState;
}

GB::CHESS_TYPE GameEngine::ProcessOrder(int row, int line)
{
	GB::CHESS_TYPE ret;

	switch (state)
	{
	case INIT_STATE:
	case FINAL_STATE:
    case AI_STATE:
		ret = GB::CHESS_NONE;
		break;
	case BLACK_STATE:
		if (data.Place(row, line, GB::CHESS_BLACK))
		{
			ret = GB::CHESS_BLACK;

            if (GameConfig::Instance()->Mode() == GB::MOD_AI_WHITE)
            {
                if (data.Judge(row, line) != GB::BLACK_WIN)
                {
                    state = AI_STATE;
                    aiThr.start();
                }                
            }
            else
            {
			    state = WHITE_STATE;
            }
		}		
		break;
	case WHITE_STATE:
		if (data.Place(row, line, GB::CHESS_WHITE))
		{
			ret = GB::CHESS_WHITE;
            if (GameConfig::Instance()->Mode() == GB::MOD_AI_BLACK)
            {
                if (data.Judge(row, line) != GB::WHITE_WIN)
                {
                    state = AI_STATE;
                    aiThr.start();
                }                
            }
            else
            {
                state = BLACK_STATE;
            }
		}
		break;
	}

	return ret;
}

void GameEngine::ModifyMode()
{
    GB::GAME_MODE mode = GameConfig::Instance()->Mode();
    if (mode == GB::MOD_AI_WHITE && 
        (state == WHITE_STATE || (state == RECORD_STATE && recordType == GB::CHESS_WHITE)))
    {
        state = AI_STATE;
        AIThrFunc();
    }
    else if (mode == GB::MOD_AI_WHITE && (state == RECORD_STATE && recordType == GB::CHESS_BLACK))
    {
        state = BLACK_STATE;
    }
    else if (mode == GB::MOD_AI_BLACK && 
            (state == BLACK_STATE || (state == RECORD_STATE && recordType == GB::CHESS_BLACK)))
    {
        state = AI_STATE;
        AIThrFunc();
    }
    else if (mode == GB::MOD_AI_BLACK && (state == RECORD_STATE && recordType == GB::CHESS_WHITE))
    {
        state = WHITE_STATE;
    }
    else if (mode == GB::MOD_2P && state == RECORD_STATE)
    {
        if (recordType == GB::CHESS_BLACK)
        {
            state = BLACK_STATE;
        }
        else
        {
            state = WHITE_STATE;
        }
    }
}

void GameEngine::SaveRecord( QString fileName )
{
    GameRecord::Save(fileName, data.Steps());
}

void GameEngine::LoadRecord( QString fileName )
{
    record.Load(fileName);

    data.Init();
    recordType = GB::CHESS_BLACK;
    state = RECORD_STATE;
}

void GameEngine::Replay()
{
    int idx = record.NextElement();

    if (idx != INT_MAX)
    {
        int row = data.Row(idx);
        int line = data.Line(idx);

        data.Place(row, line, recordType);
        emit Order(row, line, recordType);

        if (recordType == GB::CHESS_BLACK)
            recordType = GB::CHESS_WHITE;
        else
            recordType = GB::CHESS_BLACK;
    }
}
